<template>
  <WatchSize
    class="form-search"
    :class="{
      'form-search_show': showForm,
    }"
    @height-change="onHeightChange"
  >
    <FormMain
      v-show="showForm"
      ref="formMain"
      :list="list"
      :data="assertData"
      v-bind="attrs"
      :layout="layout"
      :labelPosition="labelPosition"
      :labelWidth="labelWidth"
      @submit="onSubmit"
      @visible-change="onVisibleChange"
    >
      <template
        v-for="config of list"
        :key="config.key"
        #[config.key]="scopeData"
      >
        <slot v-bind="scopeData" :name="config.key"></slot>
      </template>

      <template #default="{ mergeLayout }">
        <ElCol v-bind="mergeLayout()">
          <div class="btn-box">
            <ElButton type="primary" @mousedown="onReset">重置</ElButton>
            <ElButton type="primary" @mousedown="onSearch()">查询</ElButton>
          </div>
        </ElCol>
      </template>
    </FormMain>
  </WatchSize>
</template>
<script
  lang="ts"
  setup
  generic="
    PO extends Record<string, any>,
    SO extends Record<string, any>,
    SQ extends Record<string, any>
  "
>
import type { FormMainInstance } from "@/components/form";
import { stringifyFormData } from "@/components/form";
import WatchSize from "@/components/display/WatchSize.vue";
import type {
  ExtractFormStringifyFromObject,
  FormItemSubmitType,
  FormSearchInstance,
  FormSearchProps,
  FormSearchSearchType,
} from "./types";

type SearchQuery = ExtractFormStringifyFromObject<PO, SO> & SQ;

const props = withDefaults(defineProps<FormSearchProps<PO, SO, SQ>>(), {
  layout: () => ({
    xs: 24,
    sm: 12,
    md: 8,
    lg: 6,
    xl: 4,
  }),
  labelPosition: "right",
  labelWidth: "60px",
});

const emits = defineEmits<{
  (e: "search", data: SearchQuery, type: FormSearchSearchType): void;
  (e: "heightChange", height: number): void;
  (e: "visibleChange", status: boolean): void;
}>();

defineOptions({
  name: "FormSearch",
  inheritAttrs: false,
});

const attrs = useAttrs();

const showForm = ref(false);

const assertData = computed(() => {
  return props.data as PO;
});

const onHeightChange = (height: number) => {
  emits("heightChange", height);
};

const formMain = shallowRef<FormMainInstance>();

const getSearchQuery = (data: PO): SearchQuery => {
  return {
    ...(props.staticQuery! || {}),
    ...stringifyFormData(data, props.list),
  };
};

const onReset = () => {
  // console.log("重置", { ...props.data });
  // 重置表单
  formMain.value?.resetFields();
  emits("search", getSearchQuery(props.data), "reset");
};

const onSearch = (type: Exclude<FormSearchSearchType, "reset"> = "search") => {
  // console.log(`${type}查询`, { ...props.data });
  formMain.value?.validate().then(() => {
    // console.log("查询", { ...props.data });
    emits("search", getSearchQuery(props.data), type);
  });
};

const onSubmit = (type: FormItemSubmitType) => {
  // console.log("提交", type, { ...props.data });
  onSearch(type);
};

const expose: FormSearchInstance = {
  validate: () => {
    if (formMain.value) {
      return formMain.value.validate();
    } else {
      throw new Error("实例化未完成");
    }
  },
  resetFields: () => {
    return formMain.value?.resetFields();
  },
  clearValidate: (key?: string) => {
    return formMain.value?.clearValidate(key);
  },
  triggerReset: onReset,
  triggerSearch: () => onSearch(),
};

defineExpose(expose);

const onVisibleChange = (status: boolean) => {
  showForm.value = status;
  emits("visibleChange", status);
};
</script>
<style lang="less" scoped>
.form-search {
  &_show {
    margin-bottom: 10px;
  }
  .btn-box {
    padding-left: 20px;
  }
}
</style>
